using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace SpaceEventManager
{
    public partial class SpaceManagerGUI : Form
    {
        SpaceManager sManager;
        Boolean dragEnable;
        Boolean drag;
        Control dragControl;
        Space drawSpace;
        MainGUI main;
        double ratio;

        public SpaceManagerGUI(SpaceManager sMgr, MainGUI iMain)
        {
            dragEnable = false;
            drag = false;
            sManager = sMgr;
            main = iMain;
            drawSpace = new Space(null, null, new Point(0, 0), new Dictionary<Space, Point>());
            InitializeComponent();

            //set up listboxes that display all spaces
            foreach(Space s in sManager.DictAllSpacesNameKey.Values)
            {
                lstBxAllSpaces.Items.Add(s.Name);
                lstBxAddInnerSpace.Items.Add(s.Name);
            }
            lstBxAllSpaces.SelectedIndex = 0;
        }

        /*
         * Updates the main view, based on drawSpace */
        private void DrawSpace()
        {
            txtName.Text = drawSpace.Name;
            txtNotes.Text = drawSpace.Notes;
            txtDimX.Text = drawSpace.Dimensions.X.ToString();
            txtDimY.Text = drawSpace.Dimensions.Y.ToString();
            lstBxInSpaces.Items.Clear();

            //updates the lstBxInSpaces, which displays the innerspaces
            //of the selected space. Also shows their Location within the
            //"parent" space, separated from their name by |.
            foreach (Space s in drawSpace.InnerSpaces.Keys)
            {
                lstBxInSpaces.Items.Add(s.Name + "   |   " + drawSpace.InnerSpaces[s].X + ", " + drawSpace.InnerSpaces[s].Y);
            }
            if (lstBxInSpaces.Items.Count > 0)
            {
                lstBxInSpaces.SelectedIndex = 0;
            }
            UpdatePnlDraw();
        }

        /*
         * Updates the pnlDraw view, based on drawSpace */
        private void UpdatePnlDraw()
        {

            if (drawSpace.Name.Length > 0 && drawSpace.Dimensions.X >0 && drawSpace.Dimensions.Y >0)
            {
                Label temp = new Label();
                temp.AutoSize = false;
                temp.Text = txtName.Text;
                temp.BorderStyle = BorderStyle.FixedSingle;
                temp.Location = new Point(25, 25);

                //Runs through some calculations to maximize screen use--making sure the 
                //space being drawn uses as much of the panel as possible. This means altering
                //the space's display size to fit within the panel's dimensions.
                int width = drawSpace.Dimensions.X;
                int height = drawSpace.Dimensions.Y;
                if (width > height)
                {
                    temp.Width = pnlDraw.Width - 50;
                    ratio = Convert.ToDouble(temp.Width) / Convert.ToDouble(width);
                    temp.Height = Convert.ToInt16(height * ratio);
                }
                else
                {
                    temp.Height = pnlDraw.Height - 50;
                    ratio = Convert.ToDouble(temp.Height) / Convert.ToDouble(height);
                    temp.Width = Convert.ToInt16(width * ratio);
                }


                pnlDraw.Controls.Clear();

                //This draws the Space's innerspaces. Innerspaces are drawn with the 
                //same ratio as the parent Space.
                if(sManager.DictAllSpacesNameKey.ContainsKey(drawSpace.Name))
                {
                    foreach (Space s in drawSpace.InnerSpaces.Keys)
                    {
                        Label innerSpace = new Label();
                        innerSpace.BorderStyle = BorderStyle.FixedSingle;
                        innerSpace.AutoSize = false;
                        innerSpace.Text = s.Name;
                        innerSpace.Width = Convert.ToInt16(s.Dimensions.X * ratio);
                        innerSpace.Height = Convert.ToInt16(s.Dimensions.Y * ratio);
                        innerSpace.Left = Convert.ToInt16(25 + (drawSpace.InnerSpaces[s].X * ratio));
                        innerSpace.Top = Convert.ToInt16(25 + (drawSpace.InnerSpaces[s].Y * ratio));
                        innerSpace.MouseDown += new MouseEventHandler(innerSpace_MouseDown);
                        innerSpace.MouseMove += new MouseEventHandler(innerSpace_MouseMove);
                        innerSpace.MouseUp += new MouseEventHandler(innerSpace_MouseUp);
                        innerSpace.DoubleClick += new EventHandler(innerSpace_DoubleClick);
                        pnlDraw.Controls.Add(innerSpace);
                        
                    }
                }

                pnlDraw.Controls.Add(temp);
                pnlDraw.Invalidate();
            }
        }

        /*
         * When the mousebutton is let up, this updates the list displaying the
         * inner spaces, and sets drag to false. */
        void innerSpace_MouseUp(object sender, MouseEventArgs e)
        {
            drag = false;
            if(sender.Equals(dragControl))
            {
                lblInnerSpacePos.Visible = false;

                lstBxInSpaces.Items.Clear();
                foreach (Space s in drawSpace.InnerSpaces.Keys)
                {
                    lstBxInSpaces.Items.Add(s.Name + "   |   " + drawSpace.InnerSpaces[s].X + ", " + drawSpace.InnerSpaces[s].Y);
                }
                if (lstBxInSpaces.Items.Count > 0)
                {
                    lstBxInSpaces.SelectedIndex = 0;
                }
            }
            
        }

        /*
         * When the mouse is moved, if it is dragging an innerSpace,
         * the corresponding location of the innerSpace is changed within
         * drawSpace's InnerSpaces dictionary. The innerSpace's location within
         * must keep to the same ratio as its parent space, so some calculations
         * are needed to maintain that.*/
        void innerSpace_MouseMove(object sender, MouseEventArgs e)
        {
            if (drag == true && sender.Equals(dragControl))
            {
                foreach(Space c in drawSpace.InnerSpaces.Keys)
                {
                    if (c.Name == dragControl.Text)
                    {
                        drawSpace.InnerSpaces[c] = new Point(Convert.ToInt16(((e.X+dragControl.Left)-25)/ratio), Convert.ToInt16(((e.Y+dragControl.Top)-25)/ratio));
                        dragControl.Top = e.Y + dragControl.Top;
                        dragControl.Left = e.X + dragControl.Left;
                        lblInnerSpacePos.Text = dragControl.Text + " position: " + Convert.ToInt16(((e.X + dragControl.Left) - 25) / ratio) + ", " + Convert.ToInt16(((e.Y + dragControl.Top) - 25) / ratio);
                        break;
                    }
                }
            }
        }

        /*
         * When the mouse button is down, if it is over an innerSpace, set the 'drag' flag to true. */
        void innerSpace_MouseDown(object sender, MouseEventArgs e)
        {
            
            foreach (Control c in pnlDraw.Controls)
            {
                if (sender.Equals(c) && dragEnable)
                {
                    dragControl = c;
                    drag = true;

                    //this label displays the innerspace's position relative to the top left of the parent
                    //space, in feet.
                    lblInnerSpacePos.Visible = true;
                    lblInnerSpacePos.Text = dragControl.Text + " position: " + Convert.ToInt16(((e.X + dragControl.Left) - 25) / ratio) + ", " + Convert.ToInt16(((e.Y + dragControl.Top) - 25) / ratio);
                }
            }
        }

        /*
         * When an innerspace is doubleclicked, update the view to show that space as the main space. */
        void innerSpace_DoubleClick(object sender, EventArgs e)
        {
            string temp = sender.ToString();
            int index = temp.LastIndexOf("Text: ") + 6;
            drawSpace = sManager.DictAllSpacesNameKey[temp.Substring(index)];
            DrawSpace();
        }

        /*
         * When the Name textbox is changed, update drawSpace's name to reflect the change */
        private void txtName_TextChanged(object sender, EventArgs e)
        {
            drawSpace.Name = txtName.Text;
            try
            {
                DrawSpace();
            }
            catch
            {
            }
        }

        /* 
         * When the X dimension text box is changed, update drawSpace's x dimension to reflect the change */
        private void txtDimX_TextChanged(object sender, EventArgs e)
        {
            try
            {
                int y = drawSpace.Dimensions.Y;
                drawSpace.Dimensions = new Point(Convert.ToInt16(txtDimX.Text), y);
                DrawSpace();
            }
            catch 
            {
                txtDimX.Text = drawSpace.Dimensions.X.ToString();
                MessageBox.Show("Please use only integers as inputs for dimensions.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /*
         * When the Y dimension text box is changed, update drawSpace's y dimension to reflect the change */
        private void txtDimY_TextChanged(object sender, EventArgs e)
        {
            try
            {
                int x = drawSpace.Dimensions.X;
                drawSpace.Dimensions = new Point(x,Convert.ToInt16(txtDimY.Text));
                DrawSpace();
            }
            catch
            {
                txtDimY.Text = drawSpace.Dimensions.Y.ToString();
                MessageBox.Show("Please use only integers as inputs for dimensions.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        /*
         * Displays the selected space so that it may only be viewed. */
        private void btnViewSpace_Click(object sender, EventArgs e)
        {
            drawSpace = sManager.DictAllSpacesNameKey[lstBxAllSpaces.SelectedItem.ToString()];
            DrawSpace();
            dragEnable = false;
            txtName.Enabled = false;
            txtNotes.Enabled = false;
            txtDimX.Enabled = false;
            txtDimY.Enabled = false;
            lstBxInSpaces.Enabled = false;
            lstBxAddInnerSpace.Enabled = false;
            chkBxInnerSpace.Enabled = false;
            btnAddAsInnerSpace.Enabled = false;
            btnSaveChanges.Enabled = false;
            btnUndo.Enabled = false;
            btnRemoveInnerSpace.Enabled = false;

            UpdatePnlDraw();
        }

        /*
         * Displays the selected space so that it may be edited and viewed. */
        private void btnEdit_Click(object sender, EventArgs e)
        {
            dragEnable = true;
            drawSpace = sManager.DictAllSpacesNameKey[lstBxAllSpaces.SelectedItem.ToString()];
            DrawSpace();
            txtName.Enabled = true;
            txtNotes.Enabled = true;
            txtDimX.Enabled = true;
            txtDimY.Enabled = true;
            lstBxInSpaces.Enabled = true;
            lstBxAddInnerSpace.Enabled = true;
            chkBxInnerSpace.Enabled = true;
            btnAddAsInnerSpace.Enabled = true;
            btnSaveChanges.Enabled = true;
            btnUndo.Enabled = true;
            btnRemoveInnerSpace.Enabled = true;
            
        }

        /*
         * undoes all the changes made since editing the space by not saving the changes, and
         * calling the btnEdit action listener to display the current selected space. */
        private void btnUndo_Click(object sender, EventArgs e)
        {
            btnEdit_Click(sender, e);
        }

        /*
         * Saves the changes to the edited space, resets the main view. */
        private void btnSaveChanges_Click(object sender, EventArgs e)
        {
            sManager.UpdateSpace(drawSpace);
            lstBxAllSpaces.Items.Clear();
            lstBxAddInnerSpace.Items.Clear();
            foreach (Space s in sManager.DictAllSpacesNameKey.Values)
            {
                lstBxAllSpaces.Items.Add(s.Name);
                lstBxAddInnerSpace.Items.Add(s.Name);
            }
            lstBxAllSpaces.SelectedIndex = 0;
            main.UpdateLists();
            dragEnable = false;
            txtName.Enabled = false;
            txtNotes.Enabled = false;
            txtDimX.Enabled = false;
            txtDimY.Enabled = false;
            lstBxInSpaces.Enabled = false;
            lstBxAddInnerSpace.Enabled = false;
            chkBxInnerSpace.Enabled = true;
            btnAddAsInnerSpace.Enabled = false;
            btnSaveChanges.Enabled = false;
            btnUndo.Enabled = false;
            btnRemoveInnerSpace.Enabled = false;
        }

        /*
         * Creates a new Space, based on the information in the edit-enabled text boxes.
         * Does not allow spaces of the same name to be entered into the system. */
        private void btnCreateNew_Click(object sender, EventArgs e)
        {
            if (txtDimX.Text.Length > 0 && txtDimY.Text.Length > 0 && txtName.Text.Length > 0)
            {
                sManager.AddSpace(drawSpace);
                lstBxAllSpaces.Items.Clear();
                lstBxAddInnerSpace.Items.Clear();
                foreach (Space s in sManager.DictAllSpacesNameKey.Values)
                {
                    lstBxAllSpaces.Items.Add(s.Name);
                    lstBxAddInnerSpace.Items.Add(s.Name);
                }
                main.UpdateLists();
                dragEnable = false;
                txtName.Enabled = false;
                txtNotes.Enabled = false;
                txtDimX.Enabled = false;
                txtDimY.Enabled = false;
                lstBxInSpaces.Enabled = false;
                lstBxAddInnerSpace.Enabled = false;
                chkBxInnerSpace.Enabled = true;
                btnAddAsInnerSpace.Enabled = false;
                btnSaveChanges.Enabled = false;
                btnUndo.Enabled = false;
                btnRemoveInnerSpace.Enabled = false;
            }
            //Checks to see if a space by the same name already exists within sManager
            else if(sManager.DictAllSpacesNameKey.ContainsKey(txtName.Text))
            {
                MessageBox.Show("That space already exists. Please rename this one.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            //An input box is not completely filled out.
            else 
            {
                MessageBox.Show("Please make sure all fields are filled out.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /* 
         * if this is checked, allow the space selected in lstBxAddInnerSpace
         * to be added as an innerSpace to the space currently being edited. */
        private void chkBxInnerSpace_CheckedChanged(object sender, EventArgs e)
        {
            if (chkBxInnerSpace.Checked == true)
            {
                lstBxAddInnerSpace.Enabled = true;
                if (lstBxAddInnerSpace.Items.Count > 0)
                {
                    lstBxAddInnerSpace.SelectedIndex = 0;
                }
            }
            else
            {
                lstBxAddInnerSpace.Enabled = false;
                btnAddAsInnerSpace.Enabled = false;
            }
        }

        /* 
         * enables the AddAsInnerSpace button */
        private void lstBxAddInnerSpace_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnAddAsInnerSpace.Enabled = true;
        }

        /*
         * when the notes are changed, update drawSpace to reflect the change */
        private void txtNotes_TextChanged(object sender, EventArgs e)
        {
            drawSpace.Notes = txtNotes.Text;
        }

        /*
         * Removes the selected space from the entire system. */
        private void btnRemoveSpace_Click(object sender, EventArgs e)
        {
            if (sManager.DictAllSpacesNameKey.ContainsKey(lstBxAllSpaces.SelectedItem.ToString()))
            {
                
                if(MessageBox.Show("Are you SURE you want to delete this space?", "WARNING", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)==DialogResult.Yes)
                {
                    sManager.RemoveSpace(sManager.DictAllSpacesNameKey[lstBxAllSpaces.SelectedItem.ToString()]);
                    lstBxAllSpaces.Items.Clear();
                    lstBxAddInnerSpace.Items.Clear();
                    foreach(Space s in sManager.DictAllSpacesNameKey.Values)
                    {
                        lstBxAllSpaces.Items.Add(s.Name);
                        lstBxAddInnerSpace.Items.Add(s.Name);
                    }
                    if (lstBxAllSpaces.Items.Count > 0)
                    {
                        lstBxAllSpaces.SelectedIndex = 0;
                    }
                    main.UpdateLists();
                }
            }
        }

        /*
         * Removes the inner space from the parent space. */
        private void btnRemoveInnerSpace_Click(object sender, EventArgs e)
        {
            string sName = lstBxInSpaces.SelectedItem.ToString();
            sName = sName.Substring(0,sName.IndexOf("|")-3);
            Space sC = sManager.DictAllSpacesNameKey[sName];
            if (drawSpace.InnerSpaces.ContainsKey(sC))
            {
                if (MessageBox.Show("Are you SURE you want to delete " + sName + " from Inner Spaces?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    drawSpace.InnerSpaces.Remove(sManager.DictAllSpacesNameKey[sName]);
                    DrawSpace();
                }
            }
        }

        /*
         * Adds the selected space to the currently being edited space's list of inner spaces.
         * The new innerspace's location is 0,0 by default. */
        private void btnAddAsInnerSpace_Click(object sender, EventArgs e)
        {
            if(sManager.DictAllSpacesNameKey.ContainsKey(lstBxAddInnerSpace.SelectedItem.ToString()))
            {
                drawSpace.InnerSpaces.Add(sManager.DictAllSpacesNameKey[lstBxAddInnerSpace.SelectedItem.ToString()], new Point(0, 0));
                DrawSpace();
            }
        }

        /*
         * When the search text is changed, call sManager's search function with the text.
         * Display the results in lstBxSearchResults */
        private void txtSearch_TextChanged(object sender, EventArgs e)
        {
            List<string> foundSpaces = sManager.SearchAllSpaces(txtSearch.Text);
            lstBxSearchResults.Items.Clear();
            if (foundSpaces.Count > 0)
            {
                foreach (string s in foundSpaces)
                {
                    lstBxSearchResults.Items.Add(s);
                }
                
            }
        }

        /*
         * Exactly the same as btnViewSpace, except for lstBxSearchResults */
        private void btnSearchView_Click(object sender, EventArgs e)
        {
            drawSpace = sManager.DictAllSpacesNameKey[lstBxSearchResults.SelectedItem.ToString()];
            DrawSpace();
            dragEnable = false;
            txtName.Enabled = false;
            txtNotes.Enabled = false;
            txtDimX.Enabled = false;
            txtDimY.Enabled = false;
            lstBxInSpaces.Enabled = false;
            lstBxAddInnerSpace.Enabled = false;
            chkBxInnerSpace.Enabled = false;
            btnAddAsInnerSpace.Enabled = false;
            btnSaveChanges.Enabled = false;
            btnUndo.Enabled = false;
            btnRemoveInnerSpace.Enabled = false;

            UpdatePnlDraw();
        }

        /*
         * Exactly the same as btnEdit, except for lstBxSearchResults */
        private void btnSearchEdit_Click(object sender, EventArgs e)
        {
            dragEnable = true;
            drawSpace = sManager.DictAllSpacesNameKey[lstBxSearchResults.SelectedItem.ToString()];
            DrawSpace();
            txtName.Enabled = true;
            txtNotes.Enabled = true;
            txtDimX.Enabled = true;
            txtDimY.Enabled = true;
            lstBxInSpaces.Enabled = true;
            lstBxAddInnerSpace.Enabled = true;
            chkBxInnerSpace.Enabled = true;
            btnAddAsInnerSpace.Enabled = true;
            btnSaveChanges.Enabled = true;
            btnUndo.Enabled = true;
            btnRemoveInnerSpace.Enabled = true;
        }

        /*
         * Exactly the same as btnRemoveSpace, except using lstBxSearchResults' information */
        private void btnSearchRemove_Click(object sender, EventArgs e)
        {
            if (sManager.DictAllSpacesNameKey.ContainsKey(lstBxSearchResults.SelectedItem.ToString()))
            {

                if (MessageBox.Show("Are you SURE you want to delete this space?", "WARNING", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    sManager.RemoveSpace(sManager.DictAllSpacesNameKey[lstBxSearchResults.SelectedItem.ToString()]);
                    lstBxSearchResults.Items.Clear();
                    lstBxAddInnerSpace.Items.Clear();
                    foreach (Space s in sManager.DictAllSpacesNameKey.Values)
                    {
                        lstBxAllSpaces.Items.Add(s.Name);
                        lstBxAddInnerSpace.Items.Add(s.Name);
                    }
                    lstBxSearchResults.Items.Remove(lstBxSearchResults.SelectedItem.ToString());
                    if (lstBxSearchResults.Items.Count > 0)
                    {
                        lstBxSearchResults.SelectedIndex = 0;
                    }
                    main.UpdateLists();
                }
            }
        }
    }
}